package com.itshidu.lock.annotation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

import com.itshidu.lock.KeyGenerator;
import com.itshidu.lock.RedisLock;
import com.itshidu.lock.exception.LockException;

import java.lang.reflect.Method;

/**
 * redis 方案
 */
@Aspect
@Configuration
public class LockMethodHandler {

    @Autowired
    public LockMethodHandler(StringRedisTemplate lockRedisTemplate, KeyGenerator cacheKeyGenerator) {
        //this.lockRedisTemplate = lockRedisTemplate;
        this.cacheKeyGenerator = cacheKeyGenerator;
    }

    //private final StringRedisTemplate lockRedisTemplate;
    private final KeyGenerator cacheKeyGenerator;
    
    @Autowired RedisLock redisLock;


    //@Around("execution(public * *(..)) && @annotation(com.itshidu.demo.lock.Lock)")
    public Object interceptor(ProceedingJoinPoint pjp) {
//    	System.out.println("----- lock ------");
//        MethodSignature signature = (MethodSignature) pjp.getSignature();
//        Method method = signature.getMethod();
//        Lock lock = method.getAnnotation(Lock.class);
//		/*
//		 * if (StringUtils.isEmpty(lock.prefix())) { throw new
//		 * RuntimeException("lock key can't be null..."); }
//		 */
//        final String lockKey = cacheKeyGenerator.getLockKey(pjp);
//        String code = UUID.randomUUID().toString();
//        try {
//            //key不存在才能设置成功
//            final boolean success = lockRedisTemplate.opsForValue().setIfAbsent(lockKey, code);
//            if (success) {
//                lockRedisTemplate.expire(lockKey, lock.expire(), lock.timeUnit());
//            } else {
//                //按理来说 我们应该抛出一个自定义的 CacheLockException 异常;
//                //throw new RuntimeException("请勿重复请求");
//            	while(true) {
//            		boolean ok = lockRedisTemplate.opsForValue().setIfAbsent(lockKey, code);
//            		if(ok) {
//            			System.out.println("拿到锁:"+code);
//            			break;
//            		}
//            		try {
//						Thread.sleep(100L);
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//            	}
//            }
//            try {
//            	System.out.println("begin:"+code);
//                return pjp.proceed();
//            } catch (Throwable throwable) {
//                throw new RuntimeException("系统异常");
//            }
//        } finally {
//            //如果演示的话需要注释该代码;实际应该放开
//        	System.out.println("end:"+code);
//        	lockRedisTemplate.delete(lockKey);
//            
//        }
    	return null;
    }
    
    
	@Around("execution(public * *(..)) && @annotation(com.itshidu.lock.annotation.Lock)")
    public Object around(ProceedingJoinPoint pjp) {
    	System.out.println("----- lock ------");
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        Lock lock = method.getAnnotation(Lock.class);

        final String lockKey = cacheKeyGenerator.getLockKey(pjp);
        String code = null;
        try {
        	System.out.println("尝试获取锁...");
        	code = redisLock.lock(lockKey,lock.expire(),lock.timeUnit());
            try {
            	if(code==null||code.isEmpty()) {
            		System.out.println("获取锁超时！");
        			throw new LockException("lock : timeout.");
        		}
            	System.out.println("begin:"+code);
            	return pjp.proceed();
            } catch (Throwable throwable) {
                throw new LockException("lock : proceed error.");
            }
        } finally {
        	System.out.println("end:"+code);
        	if(lockKey!=null&&code!=null) {
        		redisLock.unLock(lockKey, code);
        	}
        }
    }
    
    
    
    
}
